/*
    This file is part of the Time-of-Flight Tracer program. It is not part of
    the original PBRT source distribution. See the included license file for
    more information.

    Copyright(c) 2014 Microsoft Corporation

    Author: Phil Pitts
*/


#include "stdafx.h"
#include "integrators/tofdirect.h"
#include "scene.h"
#include "intersection.h"
#include "paramset.h"

ToFDirectIntegrator::ToFDirectIntegrator(float lambdaMin, float lambdaMax) :
lambdaMin(lambdaMin), lambdaMax(lambdaMax) {}


ToFDirectIntegrator::~ToFDirectIntegrator() {
	delete lightDistribution;
	delete[] bsdfSampleOffset;
	delete[] lightSampleOffset;
}

void ToFDirectIntegrator::RequestSamples(Sampler *sampler, Sample *sample,
	const Scene *scene) {
	lightSampleOffset = new LightSampleOffsets[1];
	lightSampleOffset[0] = LightSampleOffsets(1, sample);
	lightNumOffset = sample->Add1D(1);
	bsdfSampleOffset = new BSDFSampleOffsets[1];
	bsdfSampleOffset[0] = BSDFSampleOffsets(1, sample);
}


void ToFDirectIntegrator::Preprocess(const Scene *scene, const Camera *camera,
	const Renderer *renderer) {
	lightDistribution = ComputeLightSamplingCDF(scene);
}


IntegrationResult ToFDirectIntegrator::Li(const Scene *scene,
	const Renderer *renderer, const RayDifferential &ray,
	const Intersection &isect, const Sample *sample, RNG &rng,
	MemoryArena &arena) const {
	// Declare common path integration variables
	vector<HistogramSample> histSamples(1);
	BSDF *bsdf = isect.GetBSDF(ray, arena);
	const Point &pc = bsdf->dgShading.p;
	const Normal &n = bsdf->dgShading.nn;

	float lightPdf;
	uint32_t lightNum = lightDistribution->SampleDiscrete(
		sample->oneD[lightNumOffset][0], &lightPdf);
	const Light *light = scene->lights[lightNum];
	BSDFSample bsdfSample(sample, bsdfSampleOffset[0], 0);
	LightSample lightSample(sample, lightSampleOffset[0], 0);

	Spectrum L = EstimateDirect(scene, renderer, arena, light, pc, n,
		-ray.d, isect.rayEpsilon, sample->time, bsdf, rng, lightSample,
		bsdfSample, BxDFType(BSDF_ALL & ~BSDF_SPECULAR)) / lightPdf;

	// Extract distance from point to light for ToF histogram
	Normal normal;
	Ray lightRay;
	light->Sample_L(scene, lightSample, rng.RandomFloat(),
		rng.RandomFloat(), sample->time, &lightRay,
		&normal, &lightPdf);
	Point pl = lightRay.o;
	
	float light2isect = Distance(pl, pc);
	float camera2isect = Distance(ray.o, pc);

	histSamples[0].distance = camera2isect + light2isect;
	// TODO remove lambdas from Camera
	histSamples[0].radiance = L.Average(lambdaMin, lambdaMax);

	return IntegrationResult(L, histSamples);
}


ToFDirectIntegrator *CreateToFDirectSurfaceIntegrator(
	const ParamSet &params) {
	float lambdaMin = params.FindOneFloat("lambdamin", 400);
	float lambdaMax = params.FindOneFloat("lambdamax", 1000);

	return new ToFDirectIntegrator(lambdaMin, lambdaMax);
}
